/*
brief: 延时参数管理。 应用场景： 用户发送一个消息，记录发送时状态（回调消息不能之间获取）， 延时回调（收到网络消息后），能获取获取发送时状态。
	代码没实现，这里代码是旧的，参考用。
	参考：如果C++进程之间通讯，最优方法用RPC
例子：

	//////////////////////////////////////////////////////////////////////////
	
	DelayParaMgr::Instance().Push(id, [](){...});// 通过lambda 外部变量 保存这次请求的参数
	send(id, ...); --发送到网络，等回调。


	//网络回调时调用
	void onRev(uint64 id, const char *msg, size_t len)
	{
		DelayParaMgr::Instance().Excute(id); //执行回调，释放函数对象内存
	}

	 //超时清理参数
	 DelayParaMgr::Instance().OnTimer();

*/

#pragma once
#include "typedef.h"
#include <vector>
#include <map>
#include <utility>
#include <time.h>



struct MyData
{
	int i=0;
};

class DelayParaMgr
{
	struct DelayData
	{
		uint64 create_tm = 0; //创建时时间戳
		uint64 id = 0;
		MyData d;
	};
	typedef std::map<uint64, DelayData> Id2DalayData;

	static const uint64 TIME_OUT_SEC = 60 * 5;  //过期时间，秒. 时间可以长点，避免动态内存重复利用产生BUG。 回调参数获取的内存不是自己的。
	Id2DalayData m_id_2_data; //参数 2 创建时间戳
	uint64 m_id_seed = 0;
	uint64 m_time_out_sec = TIME_OUT_SEC;

public:
	static DelayParaMgr &Instance()
	{
		static DelayParaMgr obj;
		return obj;
	}
	
	MyData &Push()
	{
		m_id_seed++;

		DelayData d;
		d.id = m_id_seed;
		time_t *t = (time_t *)(&d.create_tm);
		time(t);
		return m_id_2_data[d.id].d;
	}

	//失败返回nullptr
	bool Pop(uint64 id, MyData &data)
	{
		auto it = m_id_2_data.find(id);
		if (it == m_id_2_data.end())
		{
			return false;
		}
		data = it->second.d;
		m_id_2_data.erase(it);
		return true;
	}

	//建议5秒调用一次
	void CheckTimeOut()
	{
		time_t cur = 0;
		time(&cur);
		for (auto it = m_id_2_data.begin(); it != m_id_2_data.end();)
		{
			if (cur - it->second.create_tm > m_time_out_sec)
			{
				it = m_id_2_data.erase(it);
			}
			else
			{
				++it;
			}
		}
	}

	uint32_t GetParaNum()
	{
		return m_id_2_data.size();
	}
	//一般不设置，用默认的就行
	void SetTimeOutSec(uint64 sec)
	{
		m_time_out_sec = sec;
	}


private:
	DelayParaMgr() {};

};
